package com.tfswx.jcyw.ruleenginedesigner.service.impl;

import com.alibaba.fastjson.JSON;
import com.tfswx.jcyw.ruleenginedesigner.dao.GzyqXtXmMapper;
import com.tfswx.jcyw.ruleenginedesigner.dao.model.GzyqXtXm;
import com.tfswx.jcyw.ruleenginedesigner.dto.fs.FileDownloadInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.gzflgl.GzflAddInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.gzgl.BdsAddInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.gzgl.GzbdsUpdateInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.gzgl.GzdyAddInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.mxstgxgl.MxstgxAddInputDTO;
import com.tfswx.jcyw.ruleenginedesigner.dto.xmgl.*;
import com.tfswx.jcyw.ruleenginedesigner.service.*;
import com.tfswx.ruleengine.compute.bean.GzBdsDTO;
import com.tfswx.ruleengine.compute.bean.GzDataDTO;
import com.tfswx.ruleengine.compute.consts.Const;
import com.tfswx.ruleengine.compute.exception.AppException;
import com.tfswx.ruleengine.compute.gzjy.RuleEngineUtil;
import com.tfswx.ruleengine.compute.util.CommonUtil;
import com.tfswx.ruleengine.compute.util.DateUtil;
import com.tfswx.ruleengine.compute.util.EnumUtil;
import com.tfswx.ruleengine.compute.util.ZipUtil;
import com.tfswx.ruleengine.database.dto.GzImportOutputDTO;
import com.tfswx.ruleengine.database.service.GzyqService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author Ricky
 * @date 2021/5/11
 */
@Slf4j
@Service
public class XmglServiceImpl implements XmglService {
    @Resource
    private GzyqXtXmMapper gzyqXtXmMapper;
    @Resource
    private FsService fsService;
    @Resource
    private GzyqService gzyqService;
    @Resource
    private GzflService gzflService;
    @Resource
    private GzglService gzglService;
    @Resource
    private MxstgxService mxstgxService;

    @Override
    public List<XmListByRybmQueryOutputDTO> queryXmListByRybm(XmListByRybmQueryInputDTO xmListByRybmQueryInputDTO) {
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmListByRybmQueryInputDTO, gzyqXtXm);
        return gzyqXtXmMapper.queryXmListByRybm(gzyqXtXm);
    }

    @Override
    public String addXm(XmAddInputDTO xmAddInputDTO) {
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmAddInputDTO, gzyqXtXm);
        gzyqXtXm.setXmbm(CommonUtil.getUuid());
        gzyqXtXm.setSfsc("N");
        gzyqXtXm.setCjsj(new Date());
        gzyqXtXm.setZhxgsj(new Date());
        int insert = gzyqXtXmMapper.insert(gzyqXtXm);
        if (insert == 1) {
            return gzyqXtXm.getXmbm();
        }
        throw new AppException("添加项目失败");
    }

    @Override
    public boolean deleteXm(XmDeleteInputDTO xmDeleteInputDTO) {
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmDeleteInputDTO, gzyqXtXm);
        gzyqXtXm.setZhxgsj(new Date());
        int i = gzyqXtXmMapper.delete(gzyqXtXm);
        if (i != 1) {
            throw new AppException("删除失败");
        }
        return true;
    }

    @Override
    public boolean updateXm(XmUpdateInputDTO xmUpdateInputDTO) {
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmUpdateInputDTO, gzyqXtXm);
        gzyqXtXm.setZhxgsj(new Date());
        int i = gzyqXtXmMapper.update(gzyqXtXm);
        if (i != 1) {
            throw new AppException("修改失败");
        }
        return true;
    }


    @Override
    public byte[] dcGz(GzDcInputDTO gzDcInputDTO, HttpServletResponse response) throws IOException {
        GzDataDTO gzDataDTO = gzyqService.exportGz(gzDcInputDTO.getXmbm());

        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(gzDcInputDTO, gzyqXtXm);
        // 查询项目信息
        XmByXmbmQueryInputDTO xmByXmbmQueryInputDTO = new XmByXmbmQueryInputDTO();
        xmByXmbmQueryInputDTO.setXmbm(gzDcInputDTO.getXmbm());
        xmByXmbmQueryInputDTO.setRybm("0");
        XmByXmbmQueryOutputDTO xmByXmbmQueryOutputDTO = queryXmByXmbm(xmByXmbmQueryInputDTO);
        if (xmByXmbmQueryOutputDTO != null) {
            gzDataDTO.setRybm(xmByXmbmQueryOutputDTO.getRybm());
            gzDataDTO.setRymc(xmByXmbmQueryOutputDTO.getRymc());
            gzDataDTO.setXmmc(xmByXmbmQueryOutputDTO.getXmmc());
        }

        String dclx = gzDcInputDTO.getDclx();
        File gzDir = new File("gzdc");

        String version = gzDataDTO.getVersion();
        String xmmc = gzDataDTO.getXmmc();
        if ("0".equals(dclx)) {
            // 导出为规则包
            File file = new File(gzDir, CommonUtil.getUuid() + File.separator + "gzInfo.json");
            FileUtils.writeStringToFile(file, JSON.toJSONString(gzDataDTO), StandardCharsets.UTF_8);

            String fileName = xmmc + "-" + version + ".zip";
            File zipFile = new File(gzDir, fileName);
            ArrayList<File> files = new ArrayList<>();
            files.add(file);
            ZipUtil.compression(zipFile, files, Const.ZIP_PASSWORD, StandardCharsets.UTF_8);
            FileUtils.forceDelete(file.getParentFile());

            FileDownloadInputDTO fileDownloadInputDTO = new FileDownloadInputDTO();
            fileDownloadInputDTO.setFilePath(zipFile.getCanonicalPath());
            return fsService.download(fileDownloadInputDTO, response);
        } else if ("1".equals(dclx)) {
            // 导出为sql
            StringBuilder sqls = new StringBuilder();
            for (GzDataDTO.Gzfl gzfl : gzDataDTO.getGzflList()) {
                sqls.append(o2Insertsql(gzfl, "T_GZYQ_XT_GZFL")).append("\n");
                for (GzDataDTO.Gzdy gzdy : gzfl.getGzdyList()) {
                    sqls.append("\n").append("-- 规则定义 ").append(gzdy.getGzmc()).append("===开始").append("\n");
                    sqls.append(o2Insertsql(gzdy, "T_GZYQ_XT_GZDY")).append("\n");
                    for (GzDataDTO.Bds bds : gzdy.getBdsList()) {
                        sqls.append(o2Insertsql(bds, "T_GZYQ_XT_BDS")).append("\n");
                    }
                    sqls.append("-- 规则定义 ").append(gzdy.getGzmc()).append("===结束").append("\n");
                }
            }

            sqls.append("\n\n").append("-- 模型实体关系 ").append("===开始").append("\n");
            for (GzDataDTO.Mxstgx mxstgx : gzDataDTO.getMxstgxList()) {
                sqls.append(o2Insertsql(mxstgx, "T_GZYQ_XT_MXSTGX")).append("\n");
            }
            sqls.append("-- 模型实体关系 ").append("===结束").append("\n\n");

            String fileName = xmmc + "-" + version + ".sql";
            byte[] bytes = sqls.toString().getBytes(StandardCharsets.UTF_8);
            return fsService.download(bytes, fileName, response);
        } else {
            throw new AppException("不支持的导出类型");
        }
    }

    @Override
    public boolean undeleteXm(XmUndeleteInputDTO xmUndeleteInputDTO) {
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmUndeleteInputDTO, gzyqXtXm);
        gzyqXtXm.setZhxgsj(new Date());
        int i = gzyqXtXmMapper.undelete(gzyqXtXm);
        if (i != 1) {
            throw new AppException("修改失败");
        }
        return true;
    }

    @Override
    public GzImportOutputDTO drGz(GzDrInputDTO gzDrInputDTO) throws IOException {
        MultipartFile file = gzDrInputDTO.getFile();
        String originalFilename = file.getOriginalFilename();
        File gzdrDir = new File("gzdr").getCanonicalFile();
        if (!gzdrDir.exists()) {
            boolean mkdirs = gzdrDir.mkdirs();
            if (!mkdirs) {
                throw new AppException("规则包读取异常，请检查");
            }
        }
        File destFile = new File(gzdrDir, originalFilename);
        file.transferTo(destFile);
        GzDataDTO gzData = RuleEngineUtil.getGzData(destFile);
        String xmbm = gzDrInputDTO.getXmbm();

        List<GzDataDTO.Gzfl> gzflList = gzData.getGzflList();
        int gzsl = 0;
        // 插入规则分类
        for (GzDataDTO.Gzfl gzfl : gzflList) {
            GzflAddInputDTO gzflAddInputDTO = new GzflAddInputDTO();
            BeanUtils.copyProperties(gzfl, gzflAddInputDTO);
            gzflAddInputDTO.setXmbm(xmbm);
            String gzflbm = gzflService.addGzfl(gzflAddInputDTO);
            // 插入规则定义
            for (GzDataDTO.Gzdy gzdy : gzfl.getGzdyList()) {
                GzdyAddInputDTO gzdyAddInputDTO = new GzdyAddInputDTO();
                BeanUtils.copyProperties(gzdy, gzdyAddInputDTO);
                gzdyAddInputDTO.setGzflbm(gzflbm);
                String gzbm = gzglService.addGzdy(gzdyAddInputDTO);
                GzbdsUpdateInputDTO gzbdsUpdateInputDTO = new GzbdsUpdateInputDTO();
                BeanUtils.copyProperties(gzdy, gzbdsUpdateInputDTO);
                gzbdsUpdateInputDTO.setGzbm(gzbm);
                gzglService.updateGzbds(gzbdsUpdateInputDTO);
                // 插入表达式
                for (GzDataDTO.Bds bds : gzdy.getBdsList()) {
                    BdsAddInputDTO bdsAddInputDTO = new BdsAddInputDTO();
                    BeanUtils.copyProperties(bds, bdsAddInputDTO);
                    bdsAddInputDTO.setGzbm(gzbm);
                    gzglService.addBds(bdsAddInputDTO);
                }
                gzsl++;
            }
        }

        List<GzDataDTO.Mxstgx> mxstgxList = gzData.getMxstgxList();
        for (GzDataDTO.Mxstgx mxstgx : mxstgxList) {
            MxstgxAddInputDTO mxstgxAddInputDTO = new MxstgxAddInputDTO();
            BeanUtils.copyProperties(mxstgx, mxstgxAddInputDTO);
            mxstgxAddInputDTO.setXmbm(xmbm);
            mxstgxService.addMxstgx(mxstgxAddInputDTO);
        }

        GzImportOutputDTO gzImportOutputDTO = new GzImportOutputDTO();
        gzImportOutputDTO.setCurrGzyqVersion(RuleEngineUtil.getGzyqVersion());
        gzImportOutputDTO.setGzsl(gzsl);
        gzImportOutputDTO.setExptGzyqVersion(gzData.getGzyqVersion());
        gzImportOutputDTO.setVersion(gzData.getVersion());
        return gzImportOutputDTO;
    }

    @Override
    public XmByXmbmQueryOutputDTO queryXmByXmbm(XmByXmbmQueryInputDTO xmByXmbmQueryInputDTO) {
        GzyqXtXm gzyqXtXm = new GzyqXtXm();
        BeanUtils.copyProperties(xmByXmbmQueryInputDTO, gzyqXtXm);
        gzyqXtXm = gzyqXtXmMapper.queryXmByXmbm(gzyqXtXm);
        if (gzyqXtXm == null) {
            return null;
        }
        XmByXmbmQueryOutputDTO xmByXmbmQueryOutputDTO = new XmByXmbmQueryOutputDTO();
        BeanUtils.copyProperties(gzyqXtXm, xmByXmbmQueryOutputDTO);
        return xmByXmbmQueryOutputDTO;
    }

    private String o2Insertsql(Object o, String tableName) {
        BeanMap map = BeanMap.create(o);
        Set<Map.Entry<String, Object>> set = map.entrySet();
        StringBuilder names = new StringBuilder();
        StringBuilder values = new StringBuilder();
        for (Map.Entry<String, Object> entry : set) {
            String key = entry.getKey();
            if ("gzdyList".equals(key) || "bdsList".equals(key)) {
                continue;
            }
            names.append(",").append(key);
            Object value = entry.getValue();
            if (value instanceof String) {
                String v = (String) value;
                values.append(",").append("'").append(v.replace("'", "''")).append("'");
            } else if (value instanceof GzBdsDTO) {
                values.append(",").append("'").append(JSON.toJSONString(value).replace("'", "''")).append("'");
            } else if (value instanceof Date) {
                Date date = (Date) value;
                values.append(",").append("'").append(DateUtil.format(date)).append("'");
            } else if (value instanceof Enum) {
                values.append(",").append(EnumUtil.getCode(value));
            } else {
                values.append(",").append(value);
            }
        }
        names.deleteCharAt(0);
        values.deleteCharAt(0);
        return "INSERT INTO " + tableName + "(" + names + ") VALUES(" + values + ");";
    }
}
